package com.quiz.common.mybatis.core.mapper;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.quiz.common.mybatis.core.page.PageQuery;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.interfaces.MPJBaseJoin;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 自定义 Mapper 接口, 实现自定义扩展(参考ServiceImpl实现, 存在不同的mybatis-plus版本不兼容问题)
 * mybatis-plus-version : 3.5.3.1+
 *
 * @param <T> table 泛型
 * @author ahuan
 */
@SuppressWarnings("unchecked")
public interface BaseMapperPlus<T> extends MPJBaseMapper<T> {

    Log log = LogFactory.getLog(BaseMapperPlus.class);

    int DEFAULT_BATCH_SIZE = 1000;

    /**
     * 根据条件查询数据，并忽略逻辑删除
     *
     * @param queryWrapper 查询条件
     * @return {@link List }<{@link T }>
     * @author ahuan
     * @date 2023-12-20 16:23:13
     **/
    List<T> selectListIgnoreLogicDelete(@Param("ew") Wrapper<T> queryWrapper);

    /**
     * 根据条件查询数据，并忽略逻辑删除
     *
     * @param queryWrapper 查询条件
     * @return {@link T }
     * @author ahuan
     * @date 2023-12-20 16:26:54
     **/
    T selectOneIgnoreLogicDelete(@Param("ew") Wrapper<T> queryWrapper);

    /**
     * 批处理替换(忽略逻辑删除)
     *
     * @param batchList 批处理列表
     * @return int
     * @author ahuan
     * @date 2023-12-18 15:52:23
     **/
    int replaceIntoBatch(@Param("list") List<T> batchList);

    /**
     * 批处理新增或更新(忽略逻辑删除)
     *
     * @param batchList 批处理列表
     * @return int
     * @author ahuan
     * @date 2023-12-18 15:52:23
     **/
    @InterceptorIgnore(tenantLine = "true")
    int insertOrUpdateBatchIgnoreLogicDelete(@Param("list") List<T> batchList);

    /**
     * 根据ID更新(忽略逻辑删除)
     *
     * @param entity 实体对象
     * @return int
     * @author ahuan
     * @date 2023-12-20 16:57:56
     **/
    int updateByIdIgnoreLogicDelete(@Param(Constants.ENTITY) T entity);

    /**
     * 查询全部数据
     *
     * @return {@link List }<{@link T }>
     * @author ahuan
     * @date 2023-06-21 16:34:49
     **/
    default List<T> selectList() {
        return this.selectList(Wrappers.emptyWrapper());
    }

    /**
     * 批量插入
     *
     * @param entityList 实体列表
     * @return boolean
     * @author ahuan
     * @date 2023-08-18 09:47:54
     **/
    default boolean insertBatch(Collection<T> entityList) {
        return insertBatch(entityList, DEFAULT_BATCH_SIZE);
    }

    /**
     * 批量更新
     *
     * @param entityList 实体列表
     * @return boolean
     * @author ahuan
     * @date 2023-08-18 09:47:59
     **/
    default boolean updateBatchById(Collection<T> entityList) {
        return updateBatchById(entityList, DEFAULT_BATCH_SIZE);
    }

    /**
     * 批量插入或更新
     *
     * @param entityList 实体列表
     * @return boolean
     * @author ahuan
     * @date 2023-08-18 09:48:03
     **/
    default boolean insertOrUpdateBatch(Collection<T> entityList) {
        return insertOrUpdateBatch(entityList, DEFAULT_BATCH_SIZE);
    }

    /**
     * 批量插入(包含限制条数)
     *
     * @param entityList 实体列表
     * @param batchSize  批量大小
     * @return boolean
     * @author ahuan
     * @date 2023-08-18 09:48:09
     **/
    default boolean insertBatch(Collection<T> entityList, int batchSize) {
        return Db.saveBatch(entityList, batchSize);
    }

    /**
     * 批量更新(包含限制条数)
     *
     * @param entityList 实体列表
     * @param batchSize  批量大小
     * @return boolean
     * @author ahuan
     * @date 2023-08-18 09:48:13
     **/
    default boolean updateBatchById(Collection<T> entityList, int batchSize) {
        return Db.updateBatchById(entityList, batchSize);
    }

    /**
     * 批量插入或更新(包含限制条数)
     *
     * @param entityList 实体列表
     * @param batchSize  批量大小
     * @return boolean
     * @author zhanghaowen
     * @date 2023-08-18 09:48:21
     **/
    default boolean insertOrUpdateBatch(Collection<T> entityList, int batchSize) {
        return Db.saveOrUpdateBatch(entityList, batchSize);
    }

    /**
     * 插入或更新(包含限制条数)
     *
     * @param entity 实体
     * @return boolean
     * @author ahuan
     * @date 2023-08-18 09:48:25
     **/
    default boolean insertOrUpdate(T entity) {
        return Db.saveOrUpdate(entity);
    }

    /**
     * 根据条件限制查询一条数据
     *
     * @param queryWrapper 查询包装
     * @return {@link T }
     * @author ahuan
     * @date 2023-08-18 09:48:34
     **/
    default T selectLimitOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper) {
        Page<T> build = new PageQuery().build();
        build.setSize(1);
        build.setCurrent(1);
        Page<T> ts = this.selectPage(build, queryWrapper);
        if (CollectionUtils.isNotEmpty(ts.getRecords())) {
            return ts.getRecords().get(0);
        }
        return null;
    }

    /**
     * 根据 entity 条件，查询一条记录
     *
     * @param wrapper 包装器
     * @param mapper  映射器
     * @return {@link U }
     * @author ahuan
     * @date 2023-08-18 09:48:47
     **/
    default <U> U selectOne(Wrapper<T> wrapper, Function<? super T, ? extends U> mapper) {
        T obj = this.selectOne(wrapper);
        if (ObjectUtil.isNull(obj)) {
            return null;
        }
        return mapper.apply(obj);
    }

    /**
     * 根据 entity 条件，查询一条记录
     * @param field 字段
     * @param value 值
     * @return {@link T}
     */
    default T selectOne(String field, Object value) {
        return selectLimitOne(new QueryWrapper<T>().eq(field, value));
    }

    /**
     * 根据 entity 条件，查询一条记录
     * @param field 字段
     * @param value 值
     * @return {@link T}
     */
    default T selectOne(SFunction<T, ?> field, Object value) {
        return selectLimitOne(new LambdaQueryWrapper<T>().eq(field, value));
    }

    /**
     * 根据 entity 条件，查询一条记录
     * @param field1 字段1
     * @param value1 值1
     * @param field2 字段2
     * @param value2 值2
     * @return {@link T}
     */
    default T selectOne(String field1, Object value1, String field2, Object value2) {
        return selectLimitOne(new QueryWrapper<T>().eq(field1, value1).eq(field2, value2));
    }

    /**
     * 根据 entity 条件，查询一条记录
     * @param field1 字段1
     * @param value1 值1
     * @param field2 字段2
     * @param value2 值2
     * @return {@link T}
     */
    default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2) {
        return selectLimitOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2));
    }

    /**
     * 根据 entity 条件，查询一条记录
     * @param field1 字段1
     * @param value1 值1
     * @param field2 字段2
     * @param value2 值2
     * @param field3 字段3
     * @param value3 值3
     * @return {@link T}
     */
    default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2,
                        SFunction<T, ?> field3, Object value3) {
        return selectLimitOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)
                .eq(field3, value3));
    }

    /**
     * 根据 ID 查询
     *
     * @param idList id列表
     * @param mapper 映射器
     * @return {@link List }<{@link U }>
     * @author ahuan
     * @date 2023-08-18 09:49:20
     **/
    default <U> List<U> selectBatchIds(Collection<? extends Serializable> idList, Function<? super T, ? extends U> mapper) {
        List<T> list = this.selectBatchIds(idList);
        if (CollUtil.isEmpty(list)) {
            return CollUtil.newArrayList();
        }
        return list.stream().map(mapper).collect(Collectors.toList());
    }

    /**
     * 根据条件查询
     *
     * @param wrapper 包装器
     * @param mapper  映射器
     * @return {@link List }<{@link U }>
     * @author ahuan
     * @date 2023-08-18 09:49:26
     **/
    default <U> List<U> selectList(Wrapper<T> wrapper, Function<? super T, ? extends U> mapper) {
        List<T> list = this.selectList(wrapper);
        if (CollUtil.isEmpty(list)) {
            return CollUtil.newArrayList();
        }
        return list.stream().map(mapper).collect(Collectors.toList());
    }

    /**
     * 根据条件查询
     * @param field 字段
     * @param value 值
     * @return {@link List }<{@link T}>
     */
    default List<T> selectList(String field, Object value) {
        return selectList(new QueryWrapper<T>().eq(field, value));
    }

    /**
     * 根据条件查询
     * @param field 字段
     * @param value 值
     * @return {@link List }<{@link T}>
     */
    default List<T> selectList(SFunction<T, ?> field, Object value) {
        return selectList(new LambdaQueryWrapper<T>().eq(field, value));
    }

    /**
     * 根据条件查询
     * @param field 字段
     * @param values 值
     * @return {@link List }<{@link T}>
     */
    default List<T> selectList(String field, Collection<?> values) {
        if (CollUtil.isEmpty(values)) {
            return CollUtil.newArrayList();
        }
        return selectList(new QueryWrapper<T>().in(field, values));
    }

    /**
     * 根据条件查询
     * @param field 字段
     * @param values 值
     * @return {@link List }<{@link T}>
     */
    default List<T> selectList(SFunction<T, ?> field, Collection<?> values) {
        if (CollUtil.isEmpty(values)) {
            return CollUtil.newArrayList();
        }
        return selectList(new LambdaQueryWrapper<T>().in(field, values));
    }

    /**
     * 根据条件查询
     * @param field1 字段1
     * @param value1 值1
     * @param field2 字段2
     * @param value2 值2
     * @return {@link List }<{@link T}>
     */
    default List<T> selectList(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2) {
        return selectList(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2));
    }

    /**
     * 分页查询
     *
     * @param page    页面
     * @param wrapper 包装器
     * @param mapper  映射器
     * @return {@link P }
     * @author ahuan
     * @date 2023-08-18 09:49:31
     **/
    default <U, P extends IPage<U>> P selectPage(IPage<T> page, Wrapper<T> wrapper, Function<? super T, ? extends U> mapper) {
        IPage<T> pageData = this.selectPage(page, wrapper);
        IPage<U> mapperPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal());
        if (CollUtil.isEmpty(pageData.getRecords())) {
            return (P) mapperPage;
        }
        List<U> mapperCollect = pageData.getRecords().stream()
                .map(mapper)
                .collect(Collectors.toList());
        mapperPage.setRecords(mapperCollect);
        return (P) mapperPage;
    }

    /**
     * 联表分页查询
     *
     * @param page     页面
     * @param clazz    clazz
     * @param wrapper  包装器
     * @param consumer 消费者
     * @return {@link P }
     * @author ahuan
     * @date 2023-05-10 17:24:04
     **/
    default <U, P extends IPage<U>> P selectJoinPage(IPage<U> page, Class<U> clazz, MPJBaseJoin<T> wrapper, Consumer<U> consumer) {
        IPage<U> pageData = this.selectJoinPage(page, clazz, wrapper);
        if (CollUtil.isEmpty(pageData.getRecords())) {
            return (P) pageData;
        }
        pageData.getRecords().forEach(consumer);
        return (P) pageData;
    }

    /**
     * 根据 ID 查询, 自定义VO的类型
     *
     * @param id      id
     * @param voClass VO类型
     * @return {@link C }
     * @author ahuan
     * @date 2023-08-18 09:49:50
     **/
    default <C> C selectVoById(Serializable id, Class<C> voClass) {
        T obj = this.selectById(id);
        if (ObjectUtil.isNull(obj)) {
            return null;
        }
        return BeanUtil.toBean(obj, voClass);
    }

    /**
     * 查询（根据ID 批量查询）, 自定义VO的类型
     *
     * @param idList  id列表
     * @param voClass VO类型
     * @return {@link List }<{@link C }>
     * @author ahuan
     * @date 2023-08-18 09:50:00
     **/
    default <C> List<C> selectVoBatchIds(Collection<? extends Serializable> idList, Class<C> voClass) {
        List<T> list = this.selectBatchIds(idList);
        if (CollUtil.isEmpty(list)) {
            return CollUtil.newArrayList();
        }
        return BeanUtil.copyToList(list, voClass);
    }

    /**
     * 查询（根据 columnMap 条件）
     *
     * @param map     map
     * @param voClass VO类型
     * @return {@link List }<{@link C }>
     * @author ahuan
     * @date 2023-08-18 09:50:10
     **/
    default <C> List<C> selectVoByMap(Map<String, Object> map, Class<C> voClass) {
        List<T> list = this.selectByMap(map);
        if (CollUtil.isEmpty(list)) {
            return CollUtil.newArrayList();
        }
        return BeanUtil.copyToList(list, voClass);
    }

    /**
     * 根据 entity 条件，查询一条记录
     *
     * @param wrapper 包装器
     * @param voClass VO类型
     * @return {@link C }
     * @author ahuan
     * @date 2023-08-18 09:50:20
     **/
    default <C> C selectVoOne(Wrapper<T> wrapper, Class<C> voClass) {
        T obj = this.selectLimitOne(wrapper);
        if (ObjectUtil.isNull(obj)) {
            return null;
        }
        return BeanUtil.toBean(obj, voClass);
    }

    /**
     * 根据 entity 条件，查询全部记录
     *
     * @param wrapper 包装器
     * @param voClass VO类型
     * @return {@link List }<{@link C }>
     * @author ahuan
     * @date 2023-08-18 09:50:29
     **/
    default <C> List<C> selectVoList(Wrapper<T> wrapper, Class<C> voClass) {
        List<T> list = this.selectList(wrapper);
        if (CollUtil.isEmpty(list)) {
            return CollUtil.newArrayList();
        }
        return BeanUtil.copyToList(list, voClass);
    }

    /**
     * 分页查询VO
     *
     * @param page    页面
     * @param wrapper 包装器
     * @param voClass VO类型
     * @return {@link P }
     * @author ahuan
     * @date 2023-08-18 09:50:38
     **/
    default <C, P extends IPage<C>> P selectVoPage(IPage<T> page, Wrapper<T> wrapper, Class<C> voClass) {
        IPage<T> pageData = this.selectPage(page, wrapper);
        IPage<C> voPage = new Page<>(pageData.getCurrent(), pageData.getSize(), pageData.getTotal());
        if (CollUtil.isEmpty(pageData.getRecords())) {
            return (P) voPage;
        }
        voPage.setRecords(BeanUtil.copyToList(pageData.getRecords(), voClass));
        return (P) voPage;
    }

    /**
     * 查询object列表
     *
     * @param wrapper 包装器
     * @param mapper  映射器
     * @return {@link List }<{@link C }>
     * @author ahuan
     * @date 2023-09-11 17:10:21
     **/
    default <C> List<C> selectObjList(Wrapper<T> wrapper, Function<? super Object, C> mapper) {
        return this.selectObjs(wrapper).stream().filter(Objects::nonNull).map(mapper).collect(Collectors.toList());
    }
}
